/**
 * Class: PMath
 *
 * Purpose: Math for Processing
 *
 * Created: Jan 20, 2010 @ 4:49:46 PM
 * @author Ken Scott
 */
package org.openfantasia.util.math;

public class Math3D {

	public static double[][][] filter(double[][][] src, double[][][] kernal) {
		double[][][] result = copyFill(src, 0.0f);
		double scale = sum(kernal);
		double r;
		int px, py, pz;

		for (int x = 0; x < src.length; x++) {
			for (int y = 0; y < src[0].length; y++) {
				for (int z = 0; z < src[0][0].length; z++) {
					r = 0f;

					for (int i = 0; i < kernal.length; i++) {
						px = x - i;

						if (px > 0) {
							for (int j = 0; j < kernal[0].length; j++) {
								py = y - j;

								if (py > 0) {
									for (int k = 0; k < kernal[0][0].length; k++) {
										pz = z - k;

										if (pz > 0) {
											r += src[px][py][pz] * kernal[i][j][k];
										}
									}
								}
							}
						}
					}

					result[x][y][z] = r / scale;
				}
			}
		}

		return result;
	}


	public static float[][][] filter(float[][][] src, float[][][] kernal) {
		float[][][] result = copyFill(src, 0.0f);
		float scale = sum(kernal);
		float r;
		int px, py, pz;

		for (int x = 0; x < src.length; x++) {
			for (int y = 0; y < src[0].length; y++) {
				for (int z = 0; z < src[0][0].length; z++) {
					r = 0f;

					for (int i = 0; i < kernal.length; i++) {
						px = x - i;

						if (px > 0) {
							for (int j = 0; j < kernal[0].length; j++) {
								py = y - j;

								if (py > 0) {
									for (int k = 0; k < kernal[0][0].length; k++) {
										pz = z - k;

										if (pz > 0) {
											r += src[px][py][pz] * kernal[i][j][k];
										}
									}
								}
							}
						}
					}

					result[x][y][z] = r / scale;
				}
			}
		}

		return result;
	}


	public static double[][][] addNoise(double[][][] vector, double frac) {
		double[][][] result = copy(vector);
		for (int i = 0; i < vector.length; i++) {
			result[i] = Math2D.addNoise(result[i], frac);
		}
		return result;
	}


	public static float[][][] addNoise(float[][][] vector, float frac) {
		float[][][] result = copy(vector);
		for (int i = 0; i < vector.length; i++) {
			result[i] = Math2D.addNoise(result[i], frac);
		}
		return result;
	}


	public static double[][][] mulNoise(double[][][] vector, double frac) {
		double[][][] result = copy(vector);
		for (int i = 0; i < vector.length; i++) {
			result[i] = Math2D.mulNoise(result[i], frac);
		}
		return result;
	}


	public static float[][][] mulNoise(float[][][] vector, float frac) {
		float[][][] result = copy(vector);
		for (int i = 0; i < vector.length; i++) {
			result[i] = Math2D.mulNoise(result[i], frac);
		}
		return result;
	}


	public static double[][][] neg(double[][][] vector) {
		double[][][] result = copy(vector);
		for (int i = 0; i < vector.length; i++) {
			result[i] = Math2D.neg(result[i]);
		}
		return result;
	}


	public static float[][][] neg(float[][][] vector) {
		float[][][] result = copy(vector);
		for (int i = 0; i < vector.length; i++) {
			result[i] = Math2D.neg(result[i]);
		}
		return result;
	}


	public static double[][][] abs(double[][][] vector) {
		double[][][] result = copy(vector);
		for (int i = 0; i < vector.length; i++) {
			result[i] = Math2D.abs(result[i]);
		}
		return result;
	}


	public static float[][][] abs(float[][][] vector) {
		float[][][] result = copy(vector);
		for (int i = 0; i < vector.length; i++) {
			result[i] = Math2D.abs(result[i]);
		}
		return result;
	}


	public static double[][][] scale(double scale, double[][][] vector) {
		double[][][] result = copy(vector);
		for (int i = 0; i < vector.length; i++) {
			Math2D.scale(scale, result[i]);
		}
		return result;
	}


	public static float[][][] scale(float scale, float[][][] vector) {
		float[][][] result = copy(vector);
		for (int i = 0; i < vector.length; i++) {
			Math2D.scale(scale, result[i]);
		}
		return result;
	}


	public static double sum(double[][][] matrix) {
		double result = 0.0f;
		for (int x = 0; x < matrix.length; x++) {
			result += Math2D.sum(matrix[x]);
		}
		return result;
	}


	public static float sum(float[][][] matrix) {
		float result = 0.0f;
		for (int x = 0; x < matrix.length; x++) {
			result += Math2D.sum(matrix[x]);
		}
		return result;
	}


	public static double avg(double[][][] src) {
		double result = 0f;
		for (int i = 0; i < src.length; i++) {
			result += Math2D.avg(src[i]);
		}
		return result / (double) src.length;
	}


	public static float avg(float[][][] src) {
		float result = 0f;
		for (int i = 0; i < src.length; i++) {
			result += Math2D.avg(src[i]);
		}
		return result / (float) src.length;
	}


	public static double max(double[][][] matrix) {
		double result = 0.0f;
		for (int i = 0; i < matrix.length; i++) {
			double f = Math2D.max(matrix[i]);
			if (f > result) {
				result = f;
			}
		}
		return result;
	}


	public static float max(float[][][] matrix) {
		float result = 0.0f;
		for (int i = 0; i < matrix.length; i++) {
			float f = Math2D.max(matrix[i]);
			if (f > result) {
				result = f;
			}
		}
		return result;
	}


	public static double[][][] add(double[][][] a, double[][][] b) {
		double[][][] result = empty(a);
		for (int i = 0; i < a.length; i++) {
			result[i] = Math2D.add(a[i], b[i]);
		}
		return result;
	}


	public static float[][][] add(float[][][] a, float[][][] b) {
		float[][][] result = empty(a);
		for (int i = 0; i < a.length; i++) {
			result[i] = Math2D.add(a[i], b[i]);
		}
		return result;
	}


	public static double[][][] sub(double[][][] a, double[][][] b) {
		double[][][] result = empty(a);
		for (int i = 0; i < a.length; i++) {
			result[i] = Math2D.sub(a[i], b[i]);
		}
		return result;
	}


	public static float[][][] sub(float[][][] a, float[][][] b) {
		float[][][] result = empty(a);
		for (int i = 0; i < a.length; i++) {
			result[i] = Math2D.sub(a[i], b[i]);
		}
		return result;
	}


	public static double[][][] mul(double[][][] a, double[][][] b) {
		double[][][] result = empty(a);
		for (int i = 0; i < a.length; i++) {
			result[i] = Math2D.mul(a[i], b[i]);
		}
		return result;
	}


	public static float[][][] mul(float[][][] a, float[][][] b) {
		float[][][] result = empty(a);
		for (int i = 0; i < a.length; i++) {
			result[i] = Math2D.mul(a[i], b[i]);
		}
		return result;
	}


	public static double[][][] div(double[][][] a, double[][][] b) {
		double[][][] result = empty(a);
		for (int i = 0; i < a.length; i++) {
			result[i] = Math2D.div(a[i], b[i]);
		}
		return result;
	}


	public static float[][][] div(float[][][] a, float[][][] b) {
		float[][][] result = new float[a.length][a[0].length][a[0][0].length];
		for (int i = 0; i < a.length; i++) {
			result[i] = Math2D.div(a[i], b[i]);
		}
		return result;
	}


	public static double[][][] empty(double[][][] src) {
		return new double[src.length][src[0].length][src[0][0].length];
	}


	public static float[][][] empty(float[][][] src) {
		return new float[src.length][src[0].length][src[0][0].length];
	}


	public static double[][][] copy(double[][][] src) {
		double[][][] result = empty(src);

		for (int x = 0; x < src.length; x++) {
			result[x] = Math2D.copy(src[x]);
		}

		return result;
	}


	public static float[][][] copy(float[][][] src) {
		float[][][] result = empty(src);

		for (int x = 0; x < src.length; x++) {
			result[x] = Math2D.copy(src[x]);
		}

		return result;
	}


	public static double[][][] copyFill(double[][][] src, double value) {
		double[][][] result = empty(src);

		for (int x = 0; x < src.length; x++) {
			for (int y = 0; y < src[0].length; y++) {
				for (int z = 0; z < src[0][0].length; z++) {
					result[x][y][z] = value;
				}
			}
		}

		return result;
	}


	public static float[][][] copyFill(float[][][] src, float value) {
		float[][][] result = empty(src);

		for (int x = 0; x < src.length; x++) {
			for (int y = 0; y < src[0].length; y++) {
				for (int z = 0; z < src[0][0].length; z++) {
					result[x][y][z] = value;
				}
			}
		}

		return result;
	}


	public static double[][][] fill(double[][][] src, double value) {
		for (int x = 0; x < src.length; x++) {
			Math2D.fill(src[x], value);
		}

		return src;
	}


	public static float[][][] fill(float[][][] src, float value) {
		for (int x = 0; x < src.length; x++) {
			Math2D.fill(src[x], value);
		}

		return src;
	}
}